package myMq.activeMq;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;
/**
 * 当生产者在发送消息之后调用 session.rollback() 时，session.rollback() 会使生产者和 ActiveMQ broker 执行一系列操作来撤销刚刚的发送。这种回滚机制确保消息在发送失败时不会进入消息队列，也不会被消费者接收。以下是生产者和 broker 的操作过程：
 *
 * 生产者端的操作
 *
 * 	1.	撤销消息发送记录：session.rollback() 会通知生产者撤销刚刚在事务中执行的所有操作。
 * 	2.	消息状态重置：在事务回滚后，该 Session 下的所有消息发送状态会被重置为未发送。这意味着当前的消息不会再进入消息队列。
 * 	3.	重新准备事务：rollback 后，Session 会进入一个清理状态，并重新准备开始一个新的事务。这使得生产者可以在回滚后继续使用同一个 Session 来重新执行其他操作。
 *
 * Broker 端的操作
 *
 * 	1.	消息丢弃：由于事务未提交，broker 不会持久化（或非持久化）消息到队列或主题中。如果消息已暂时保存，broker 会将其丢弃，以确保未提交事务中的消息不会被其他消费者接收。
 * 	2.	资源释放：broker 将释放分配给该事务的资源，包括内存或临时存储空间。对于持久化的消息（若在事务中指定为持久化），broker 会删除任何未提交的持久化消息存储。
 * 	3.	确认事务状态：broker 会将该消息的状态标记为未提交，并确保不会有消费者读取该消息。这是确保事务性消息传递一致性的一部分。
 *
 * 实际效果
 *
 * session.rollback() 的直接结果是，生产者发送的消息完全从 broker 中移除，无论是暂时存储在内存中还是已写入持久化存储的部分数据。在下一个事务开始前，该消息完全不可见，保持了消息传递的原子性和一致性。
 *
 * 示例代码
 *
 * Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
 * MessageProducer producer = session.createProducer(destination);
 * TextMessage message = session.createTextMessage("Transaction Message");
 *
 * try {
 *     producer.send(message);
 *     // 模拟异常，回滚事务
 *     session.rollback(); // 此时消息不会进入队列
 * } catch (Exception e) {
 *     session.rollback(); // 确保事务回滚
 * }
 *
 * 总结
 *
 * 调用 session.rollback() 后，生产者会丢弃当前事务中的发送操作，而 broker 会撤销对该消息的任何存储或处理，确保消息不会传递到消费者或持久化。这一过程保证了事务消息传递的完整性和一致性。
 *
 */


/**
 * 在 ActiveMQ 中，broker 在收到事务内的消息后、等待事务提交之前，会将消息暂时存储在内存或临时存储中，而不会将其真正持久化。这种临时存储机制确保了消息在事务提交前不会被持久化到磁盘，同时也不会被消费者接收到。以下是更详细的存储过程：
 *
 * 存储过程
 *******************************************************************************
 * 	1.	内存缓冲：在大多数情况下，事务性消息会被暂时保存在内存缓冲区中，等待事务的最终确认或回滚。
 * 	2.	临时存储：如果事务过程中发送的消息数量较大，超过了内存缓冲区限制，broker 可能会将部分消息写入临时文件，以确保不会因为内存溢出而影响消息传递。
 *******************************************************************************
 *
 *
 * 这种设计的优点是，在等待事务提交期间，消息不会被写入磁盘的持久存储，从而避免不必要的磁盘 I/O 操作，提升了性能。
 *
 * 事务提交后的处理
 *
 * 	•	事务提交：一旦事务提交 (session.commit())，broker 会将消息写入持久存储（如 KahaDB、JDBC 数据库等）以确保持久性，然后将其标记为可消费。
 * 	•	事务回滚：如果事务回滚 (session.rollback())，broker 会从内存或临时文件中删除该消息，确保不会被消费或持久化。
 *
 * 持久化消息的例外
 *
 * 对于持久化消息，即使在事务提交前 broker 也不会直接写入最终的持久化存储位置。消息提交之前，只有事务性的临时存储，而非持久化文件系统中的存储。
 */
public class QueueProducer {

    /**
     * 默认用户名
     */
    public static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
    /**
     * 默认密码
     */
    public static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
    /**
     * 默认连接地址
     */
    public static final String BROKER_URL = ActiveMQConnection.DEFAULT_BROKER_URL;

    public static void main(String[] args) {
        //创建连接工厂
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
        try {
            //创建连接
            Connection connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //创建会话
            Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
            //创建 Queue，需指定其对应的队列名称，消息生产者和消费者将根据它来发送、接收对应的消息。
            Queue myTestQueue = session.createQueue("activemq-queue-test1");
            //消息生产者
            MessageProducer producer = session.createProducer(myTestQueue);
            //设置非持久化    activeMQ默认为消息持久化
//            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            //s设置过期时间  默认情况下消息永不过期
//            producer.setTimeToLive();
            //创建一条消息对象
            TextMessage message = session.createTextMessage("测试点对点的一条消息555");
            //发送一条消息
            producer.send(message);
            //事务提交
            session.commit();

            //事务回滚
//           session.rollback();

            //关闭资源
            session.close();
            connection.close();
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }

}
